[Nekaj (mogoce vecino) tega ste verjetno ze slisali v srednji soli,
ker pa ne vem tocno, koliko, sem stvari tule raje napisal bolj na
siroko.  Ce vam bo kaj ze prevec domace, pa preskocite.  Tudi tisto
o diofantskih enacbah na koncu lahko verjetno brez pretirano velike
skode preskocite, ce vas ne zanima.]

Na koncu vsakega razdelka so tudi linki na nekaj nalog, ki uporabljajo
pojme, predstavljene v tistem razdelku.  Kot obicajno vam priporocam, da
kaksno od teh nalog resite.

--

Odkrivanje prastevil

Vcasih pride prav, ce imamo pri roki vsa prastevila, manjsa od n.
Ce n ni le prevec gromozanski, si lahko pomagamo z Eratostenovim resetom.
Ce bi to poceli rocno, bi slo nekako tako: zapisimo si stevila od
2 do n (recimo, da je n = 50):
   2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ... 49 50
Vemo, da je 2 prastevilo, njeni veckratniki pa seveda niso prastevila.
Zato jih vrzimo ven iz nasega seznama:
   (2) 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49
Prvo izmed teh, ki so ostala v seznamu (torej stevilo 3), mora biti
prastevilo, kajti ce bi bilo sestavljeno, bi bilo veckratnik kaksnega
manjsega prastevila -- edino manjse prastevilo pa je 2 in njegove
veckratnike smo ze zbrisali iz seznama.  Torej je 3 prastevilo.
Zdaj lahko zbrisemo iz seznama njegove veckratnike:
   (2 3) 5 7 11 13 17 19 23 25 29 31 35 37 41 43 47 49
Prvo izmed teh, ki so ostala (torej stevilo 5) mora biti tudi prastevilo,
o cemer se lahko prepricamo z enakim razmislekom kot prej.  Zbrisimo se
njegove veckratnike:
   (2 3 5) 7 11 13 17 19 23 29 31 37 41 43 47 49
V naslednjem koraku ugotovimo, da je 7 prastevilo, in pobrisimo njene
veckratnike:
   (2 3 5 7) 11 13 17 19 23 29 31 37 41 43 47
Ce bi zdaj s tem postopkom nadaljevali, bi se izkazalo, da ne zbrisemo
nobenega stevila vec.  Tako bi na koncu ugotovili, da so vsa ta preostala
stevila prastevila:
 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
Tako smo dobili vsa prastevila od 1 do 50.

Temu postopku pravijo Eratostenovo reseto (ali Eratostenovo sito).
Izvor tega imena je menda v analogiji, da nam stevila padajo iz
seznama, kot da bi jih sejali skozi reseto, na koncu pa nam ostanejo
le tista, ki jih hocemo, torej prastevila.

Na tejle strani je applet, ki ilustrira ta postopek:
http://www.math.utah.edu/~alfeld/Eratosthenes.html
Pa se malo o Eratostenu:
http://www-gap.dcs.st-and.ac.uk/~history/Mathematicians/Eratosthenes.html

To lahko zdaj zapisemo kot postopek.  Namesto seznama stevil
bomo uporabili kar tabelo, ki za vsako stevilo pove, ali je se
v seznamu ali ne vec.

var JePrastevilo: array[1..n] of Boolean;
    k: Integer;
begin
  (* Za 1 ze vemo, da ni prastevilo, za ostala stevila pa
     zaenkrat oznacimo, kot da so. *)
  JePrastevilo[1] := False;
  for k := 2 to n do JePrastevilo[k] := True;
  for k := 2 to n do
    if JePrastevilo[k] then
      begin
      WriteLn(k, ' je prastevilo.');
      (* Za k-jeve veckratnike oznacimo, da niso prastevila. *)
      j := k + k;
      while j <= n do
        begin
        JePrastevilo[j] := False;
        j := j + k;
        end;
      end;
end;

Ta postopek je mogoce se izboljsati, na primer na naslednje nacine:

- Namesto tabele booleanov, ki zasedejo verjetno vsak vsaj en bajt,
  bi imeli tabelo bajtov, v kateri bi vsakemu stevilu posvetili samo
  en bit -- vec kot toliko namrec tako ali tako ne potrebujemo.
  S tem bi prihranili veliko pomnilnika.  Le dostop do teh podatkov
  bi se malo zapletel -- namesto preprostega JePrastevilo[i]
  bi morali preracunati, v katerem bajtu se nahaja podatek za stevilo
  i in v katerem bitu tega bajta se nahaja.

- Se ena dovolj enostavna izboljsava je, da obravnavamo prastevilo 2
  posebej.  Prva stvar, ki jo gornji postopek naredi, je ta, da
  pomece iz seznama vsa soda stevila (razen stevila 2, ki ga
  razglasi za prastevilo).  Ocitno mu lahko to opravilo prihranimo,
  ce ze na zacetku posebej dolocimo, da je 2 prastevilo,
  sodih stevil pa sploh ne hranimo v tabeli JePrastevilo.
  Namesto n bitov potrebujemo zdaj le se n/2 bitov pomnilnika,
  po en bit za vsako liho stevilo.  Seveda je dostop do podatkov
  o tem, ali je nekaj se oznaceno kot prastevilo ali ne, zdaj
  se malo bolj zapleten.  Dodatna lepota je, da j-ja potem ni
  treba povecevati za k, pac pa ga lahko za 2*k -- kajti k bo
  vedno brez izjeme lih, njegovi veckratniki pa zato pac
  izmenicno lihi in sodi; za nas je dovolj, ce gre j le po lihih.

- Ko oznacujemo k-jeve veckratnike, da niso prastevila, nima smisla
  zaceti pri 2*k, 3*k, 4*k, itd. --- 2*k je veckratnik stevila 2,
  3*k je veckratnik stevila 3, 5*k je veckratnik stevila 5 in tako
  naprej, torej smo pri vseh teh ze prej ugotovili, da niso
  prastevila, zato nima smisla, da jih zdaj se enkrat pregledujemo.
  Namesto j := k + k bi torej gornja zanka lahko zacela kar pri
  j := k * k -- vsi veckratniki k-ja pred k*k imajo namrec kaksnega
  delitelja, manjsega od k, torej smo morali zanje ze ugotoviti,
  da niso prastevila.

- Dodatna korist razmisleka iz prejsnjega odstavka pa je, da zdaj
  vemo, da nima smisla gledati takih k, pri katerih je k*k > n,
  saj takrat ne bomo nicesar vec spremenili -- ce je neko stevilo
  manjse ali enako n in je sestavljeno, mora imeti enega od deliteljev
  manjsega ali enakega n^2.  Torej, kar je do n sestavljenih stevil,
  smo jih ze odkrili, ko smo z k prisli do Sqrt(n).

(* Zanimajo nas prastevila od 1 do n.
   V tabeli si bomo vzeli po en bit za vsako liho stevilo od 1 do n.
   Prvi bajt bo tako lahko hranil podatke o stevilih 1, 3, 5, 7,
   9, 11, 13, 15; naslednji o 17, 19, 21, 23, 25, 27, 29, 31; itd.
   Skratka, stevilo bajtov, ki jih potrebujemo, je
   n/16, zaokrozeno navzgor.  To lahko izracunamo kot (n + 15) div 16.
   Tabelo Reseto bomo indeksirali od 0 naprej; bit b na indeksu i
   bo predstavljal stevilo 16*i + 2*b + 1.  V obratno smer: ce je
   k neko liho stevilo, ga bomo nasli na indeksu k div 16,
   v bitu (k div 2) mod 8. *)
const nBytes = (n + 15) div 16;
var Reseto: array[0..nBytes-1] of Byte;
    I, J, K: Integer;
begin
  (* Za 1 ze vemo, da ni prastevilo, za ostala stevila pa
     zaenkrat oznacimo, kot da so. *)
  Reseto[0] := $FE; (* bit 0 ugasnjen, ostali prizgani *)
  for i := 1 to nBytes-1 do Reseto[i] := $FF; (* vsi biti prizgani *)
  (* Stevila 2 nimamo v tem resetu, vemo pa, da je prastevilo. *)
  WriteLn(2, ' je prastevilo.');
  (* Zdaj pa si oglejmo ostala stevila. *)
  k := 3;
  while k * k <= n do
    begin
    (* Preveriti moramo, ce je bit (k div 2) mod 8 na indeksu
       k div 16 se prizgan. *)
    if (Reseto[k div 16] and (1 shl ((k div 2) mod 8))) <> 0 then
      begin
      WriteLn(k, ' je prastevilo.');
      (* Za k-jeve veckratnike oznacimo, da niso prastevila. *)
      j := k * k; (* k je lih, torej je k*k tudi lih *)
      while j <= n do
        begin
        Reseto[j div 16] := Reseto[j div 16] and
          not (1 shl ((j div 2) mod 8));
        (* Pojdimo na naslednji lihi veckratnik k-ja. *)
        j := j + 2 * i;
        end;
      end;
    (* Pojdimo s k-jem na naslednje liho stevilo. *)
    k := k + 2;
    end;
  (* Zdaj poznamo vsa prastevila od 1 do n.  To so:
     - stevilo 2
     - vsa tista liha stevila, ki imajo v tabeli Reseto prizgan
       pripadajoci bit.
     Doslej smo s stavki WriteLn izpisali ze vsa prastevila do
     trenutne vrednosti k.  Ce bi hoteli zdaj izpisati se
     preostala, lahko naredimo takole: *)
  while k < n do
    begin
    if (Reseto[k div 16] and (1 shl ((k div 2) mod 8))) <> 0 then
      WriteLn(k, ' je prastevilo.');
    k := k + 2;
    end;
end;

Tale podprogram je prastevila le izpisoval, lahko pa bi z njimi
seveda poceli tudi kaj drugega.  Lahko bi si jih zapisovali v
kaksno tabelo ali seznam, lahko pa bi tudi le obdrzali reseto
in kasneje z njegovo pomocjo poceni preverjali, ali je doloceno
(liho) stevilo prastevilo ali ne.

Za obcutek (ki zna biti koristen, ce boste morali prastevila
kdaj shranjevati v kaksno tabelo, pa bi radi vedeli, koliksno
je pametno rezervirati) lahko povemo, da obstaja 168 prastevil,
manjsih od 1000; 6542 manjsih od 65536; 78498 manjsih od
milijona; 664579 manjsih od 10 milijonov; 5761455 manjsih od sto
milijonov.  V splosnem velja, da je stevilo prastevil, manjsih
od n, priblizno n/(ln(n)-1).

Cel kup zanimivih reci o prastevilih je na
http://www.utm.edu/research/primes .

Primer naloge, kjer pride prav (veliko) Eratostenovo reseto:
  http://acm.uva.es/p/v103/10311.html
Prav pride tudi pri vec drugih nalogah, kjer potrebujemo
prastevila, le da ne nujno tako velika.

--

Razcep na prafaktorje

Vcasih je koristno neko pozitivno celo stevilo n razcepiti na
prafaktorje.  Spomnimo se, da to v bistvu pomeni, da ga izrazimo
kot produkt prastevil.  Na primer:
  360 = 2 * 180 = 2 * 2 * 90 = 2 * 2 * 2 * 45 = 2
      = 2 * 2 * 2 * 3 * 15 = 2 * 2 * 2 * 3 * 3 * 5
ali, krajse, 360 = 2^3 * 3^2 * 5.

Kadar delamo to rocno, gremo obicajno od manjsih prastevil proti
vecjim in pri vsakem preverimo, ali je nas n deljiv z njim
(oz. kolikokrat je).  Tudi z racunalnikom se pravzaprav ne da
narediti dosti bolje.  Recimo, da imamo v neki tabeli dovolj
najmanjsih prastevil in je Prast[i] i-to najmanjse prastevilo.

procedure Razcep(n: Integer);
var i: Integer;
begin
  i := 1;
  while n > 1 do
    begin
    if (n mod Prast[i]) = 0 then
      begin
      WriteLn(Prast[i]);
      n := n div Prast[i];
      end
    else
      i := i + 1;
    end;
end;

Ce bi temu podprogramu dali kot parameter stevilo 360, bi (upajmo)
izpisal 2, 2, 2, 3, 3 in 5.  Pogosto je koristno, da dobimo vsak
prafaktor le enkrat, zraven pa se njegovo stopnjo:

procedure Razcep(n: Integer);
var i, d: Integer;
begin
  i := 1;
  while n > 1 do
    begin
    d := 0;
    while (n mod Prast[i]) = 0 do
      begin
      d := d + 1;
      n := n div Prast[i];
      end;
    if d > 0 then
      WriteLn(Prast[i], '^', d);
    i := i + 1;
    end;
end;

Ta razlicica bi (upajmo) pri n = 360 izpisala 2^3, 3^2 in 5.

Koristen pa je se naslednji razmislek: recimo, da smo v n-ju
odkrili ze vse prafaktorje, manjse od p.  Ce se zdaj recimo v
n-ju pojavljata se vsaj dva razlicna prafaktorja, bosta oba
vecja ali enaka p, zato bo n vecji ali enak p^2.  Podobno, ce
se v n-ju pojavlja se nek neodkrit prafaktor s stopnjo, vecjo od
1, mora biti n tudi vecji ali enak p^2.  To pa pomeni, da, ko
nasa zunanja zanka while pride do prastevil, ki so vecja od
Sqrt(n), mora biti vse, kar nam je od n-ja preostalo, le se
en sam prafaktor, zato se lahko takrat takoj ustavimo.
Prijetna posledica je, da, ce hocemo biti sposobni razcepiti
poljubno stevilo, manjse od M, potrebujemo le prastevila do
Sqrt(M).  Na primer: ce bomo cepili stevila, manjsa od 2^32,
potrebujemo le prastevila do 65536, torej le 6542 prastevil.

procedure Razcep(n: Integer);
var i, d: Integer;
begin
  i := 1;
  while n > 1 do
    begin
    if Prast[i] * Prast[i] > n then Break;
    d := 0;
    while (n mod Prast[i]) = 0 do
      begin
      d := d + 1;
      n := n div Prast[i];
      end;
    if d > 0 then
      WriteLn(Prast[i], '^', d);
    i := i + 1;
    end;
  if n > 1 then WriteLn(n, '^', 1);
end;

Seveda v praksi prafaktorjev najbrz ne bi le izpisovali
na zaslon, ampak bi si jih kam shranili (oz. bi si shranili
pare (prafaktor, stopnja), kot na primer (2, 3), (3, 2)
in (5, 1) pri n = 360).

Razcep na prafaktorje lahko pride prav npr. v primerih,
ko bo treba racunati nekaj, kar bo na koncu sicer mogoce
slo v 32 bitov ali kaksno podobno stevilko, vmesni rezultati
pa so lahko tudi gromozanski.

Primeri nalog, kjer pride prav razcep na prafaktorje:

http://acm.uva.es/p/v4/443.html [lahka]
http://acm.uva.es/p/v3/367.html
http://acm.uva.es/p/v3/369.html
http://acm.uva.es/p/v103/10329.html
Za zadnji dve si je mogoce koristno prej prebrati razdelek
o permutacijah (spodaj v tem mailu).
http://acm.uva.es/p/v103/10303.html

--

Najvecji skupni delitelj, najmanjsi skupni veckratnik

Te reci verjetno ze poznate.  Kot pove ze ime, je najvecji
skupni delitelj dveh (ali vec) stevil najvecje tako stevilo,
ki deli vsa ta stevila.  Ce imamo pri rokah razcepe na
prafaktorje, je zadeva zelo enostavna: recimo, da je
  a = p_1 ^ a_1 * p_2 ^ a_2 * ... * p_n ^ a_n,
  b = p_1 ^ b_1 * p_2 ^ b_2 * ... * p_n ^ b_n;
torej se prafaktor p_i v razcepu stevila a pojavlja a_i-krat,
v razcepu stevila b pa b_i-krat.  Seveda ni nujno, da imata
a in b iste prafaktorje, zato je lahko kaksna vrednost a_i
ali pa b_i tudi enaka 0.
  No, naj bo c najvecji skupni delitelj stevil a in b.
To oznacimo tudi z gcd(a, b) ("greatest common divisor").
Recimo, da p^d deli c za neko prastevilo p in neko stopnjo d.
Ker c deli a in b, mora p^d deliti tudi a in b. Se pravi, da
lahko v razcepu c-ja na prafaktorje nastopajo le tista
prastevila, ki nastopajo tudi v razcepu a-ja in b-ja.
In ce zdaj recimo p_i^d deli c, to pomeni, da mora imeti
p_i v razcepu a-ja in b-ja stopnjo vsaj d.  Z drugimi besedami,
a_i >= d in b_i >= d.  Da pa bo c najvecji skupni delitelj,
mora biti seveda d v okviru teh omejitev cim vecji; torej
naj bo d = min(a_i, b_i).
  Na primer: a = 1560 = 2 * 2 * 2 * 3 * 5 * 13,
             b = 3276 = 2 * 2 * 3 * 3 * 7 * 13.
V skupnem delitelju a-ja in b-ja se lahko pojavljajo samo
prastevila 2, 3 in 13, saj so to edina prastevila, ki nastopajo
tako v razcepu a-ja kot v razcepu b-ja.  Za povrhu lahko
2 nastopa najvec dvakrat (ker v b nastopa samo dvakrat,
v a pa trikrat), 3 najvec enkrat (ker v a nastopa samo
enkrat, ceprav v b dvakrat), 13 pa tudi najvec enkrat (ker
v obeh nastopa le po enkrat).  Najvecji skupni delitelj
a-ja in b-ja je torej 2 * 2 * 3 * 13 = 156.

Ce imamo a in b ze predstavljena z zaporedjem parov
(prafaktor, stopnja) in so ti pari urejeni po (recimo)
narascajocih vrednostih prafaktorjev, lahko zaporedji
preprosto "zlijemo".  Zacnemo na zacetku in primerjamo
trenutna prafaktorja:
  a = 2^3 * 3^1 * 5^1 * 13^1, b = 2^2 * 3^2 * 7^1 * 13^1.
      ~~~                         ~~~
Ker sta enaka, bo ta prafaktor nastopal tudi v gcd-ju
in sicer z manjso od obeh stopenj -- tu torej z min(3, 2).
Zato si zapomnimo: 2^2.  Premaknimo se naprej.
  a = 2^3 * 3^1 * 5^1 * 13^1, b = 2^2 * 3^2 * 7^1 * 13^1.
            ~~~                         ~~~
Kot prej -- oba sta enaka, min(1, 2) = 1, zapomnimo si 3^1.
  a = 2^3 * 3^1 * 5^1 * 13^1, b = 2^2 * 3^2 * 7^1 * 13^1.
                  ~~~                         ~~~
Tu imamo razlicna prafaktorja.  5 je manjsa od 7, zato
se v razcepu b-ja prafaktor 5 ne more pojaviti (ce bi se,
bi se moral pred 7, saj smo rekli, da imamo urejene
prafaktorje).  Pac pa je naceloma mogoce, da se 7 pojavi v
razcepu a-ja, zato se po a-ju tokrat ne premaknimo.
  a = 2^3 * 3^1 * 5^1 * 13^1, b = 2^2 * 3^2 * 7^1 * 13^1.
                        ~~~~                  ~~~
Zdaj imamo 13 in 7, torej se 7 v a-ju ne more pojaviti
(pac pa se lahko 13 se pojavi v b-ju), zato se po b-ju
premaknimo naprej.
  a = 2^3 * 3^1 * 5^1 * 13^1, b = 2^2 * 3^2 * 7^1 * 13^1.
                        ~~~~                        ~~~~
Zdaj imamo 13 in 13, zato si zapomnimo 13^1.
  Ce zmnozimo vse, kar smo si zapomnili, dobimo ravno
2^2 * 3^1 * 13^1 = 156, torej skupni delitelj a-ja in b-ja.

Lepo pri tem postopku je, da lahko na isti nacin zlivamo
zraven se po vec zaporedij hkrati in tako dobimo najvecji
skupni delitelj vec stevil naenkrat.

Prav tak postopek je uporaben tudi za najmanjsi skupni
veckratnik (lcm = least common multiple).  Ce se p_i pojavlja
v razcepu a-ja s stopnjo a_i, v razcepu b-ja pa s stopnjo b_i,
se bo moral v razcepu vsakega njunega skupnega veckratnika s
stopnjo, ki je >= a_i in >= b_i.  Da bo skupni veckratnik cim
manjsi, vzemimo najmanjso stopnjo, ki ustreza temu pogoju,
torej max(a_i, b_i).
  Na primer: a = 1560 = 2 * 2 * 2 * 3 * 5 * 13,
             b = 3276 = 2 * 2 * 3 * 3 * 7 * 13.
Imamo prafaktorje 2 (v a-ju s stopnjo 3, v b-ju s stopnjo
2; v lcm torej s stopnjo 3), 3 (v a-ju s stopnjo 1, v b-ju
s stopnjo 2; v lcm torej s stopnjo 2); 5 (v a-ju s stopnjo 1,
v b-ju s stopnjo 0; v lcm torej s stopnjo 1); 7 (v lcm-ju
s stopnjo 1), 13 (v lcm-ju s stopnjo 1).  Torej je
  lcm(a, b) = 2^3 * 3^2 * 5 * 7 * 13 = 32760.

No, za najvecji skupni delitelj obstaja v resnici se en
algoritem, ki temelji na malo bolj matematicnem razmisleku.
Naj bo d = gcd(a, b) in recimo, da je a > b.  Potem je
a oblike a' * d (za nek a'), b pa oblike b' * d (za nek b')
in a' in b' sta si tuja (nimata nobenega skupnega delitelja
-- sicer bi lahko tega vkljucili v d in imeli potem nek skupni
delitelj a-ja in b-ja, ki bi bil se vecji od d, mi pa smo
predpostavili, da je d najvecji).  Rekli smo, naj bo a > b.
Ce bi delili a z b, bi dobili nek kolicnik k in ostanek o:
     a = k * b + o.
In ce upostevamo a = a' d, b = b' d:
     a' d = k b' d + o
     d (a' - k b') = o.
Ostanek o je torej veckratnik d-ja.  d torej ni le skupni
delitelj a-ja in b-ja, ampak tudi delitelj o-ja.  Najvecji
skupni delitelj o-ja in b-ja je torej vecji ali enak d.
Ali je mogoce, da bi imela o in b se kak vecji skupni delitelj?
Ta bi bil potem oblike D = d * d'.  Vse, kar prinese d', bi
torej moralo v o priti prek clena (a' - k b'), ki bi bil torej
veckratnik d': a' - k b' = d" * d'.  Podobno bi vse, kar
prinese d' v b, moralo priti tja prek clena b' (saj je
b = d * b'), torej je b' = b" * d'.  Torej imamo
a' - k b" d' = d" d', torej a' = k b" d' + d" d',
torej a' = a" d' za a" = k b" + d".  To pa pomeni,
da je a = a' d tudi oblike a" d' d = a" D, torej je D
tudi delitelj a-ja.  Torej gcd(a, b) v resnici ni d, ampak D;
prisli smo do protislovja.  Zato je nemogoce, da bi imela
o in b kak vecji skupni delitelj od d-ja.  To pa pomeni, da je
  gcd(a, b) = gcd(b, o).
o pa je ostanek pri deljenju a-ja z b: torej o = a mod b.
Torej gcd(a, b) = gcd(b, a mod b).  Ce je ostanek o enak 0,
pa to pomeni, da je a veckratnik b-ja in v tem primeru je
gcd(a, b) kar enako b.  Zdaj imamo naslednji postopek:

function Gcd(a, b: Integer): Integer;
var o: Integer;
begin
  while b > 0 do
    begin
    o := a mod b;
    a := b; b := o;
    end;
  Gcd := a;
end;

Ta postopek deluje tudi, ce zacnemo z a < b, saj bo v
tem primeru izracunal o = a mod b = a in bo tako v bistvu le
obrnil a in b ter potem nadaljeval brez problemov.
(Mimogrede, ta postopek se imenuje Evklidov algoritem.
Lahko bi rekli, da je eden od najstarejsih netrivialnih
algoritmov.  Menda ga dejansko omenja ze Evklid v svojih
Elementih.)

Primer skozi nekaj zaporednih korakov:
                a     b
              1560 3276
              3276 1560
              1560  156
               156    0
in podprogram vrne 156, kot je prav.

Ce bi hoteli racunati gcd vec stevil, bi si morali pac pomagati
z dejstvom, da je gcd(a, b, c) = gcd(gcd(a, b), c) in podobno.
Isto seveda velja tudi za lcm.

Se ena koristna zveza:
    gcd(a, b) * lcm(a, b) = a * b.
O tem se lahko prepricamo, ce si ogledamo tisti nas postopek
z zlivanjem prafaktorjev in se spomnimo, da vedno velja:
    min(a_i, b_i) + max(a_i, b_i) = a_i + b_i.
Ne velja pa to seveda vedno za gcd in lcm vec stevil, npr.
    gcd(10, 20, 30) = 10
    lcm(10, 20, 30) = 60
    10*60 = 600,  10*20*30 = 6000.

Primeri nalog, kjer prideta prav gcd in lcm:
- http://acm.uva.es/p/v4/408.html
- http://acm.uva.es/p/v4/463.html
- [koristno je prej prebrati naslednji razdelek
  o permutacijah] imamo neko permutacijo p in iscemo najmanjse
  pozitivno celo stevilo n, za katero velja: ce elemente n-krat
  zapored preuredimo s permutacijo p, pridejo spet v
  razporeditev, s katero so zaceli.

--

Permutacije

Permutacije so v bistvu prerazporeditve stvari.  Ce imamo n
razlicnih stvari, na koliko nacinov jih lahko postavimo v
zaporedje?

Recimo, da imamo tri stvari: 1, 2, 3.  Potem jih lahko
razvrstimo na 6 nacinov:
  1 2 3      1 3 2      2 1 3     2 3 1     3 1 2    3 2 1
Ce imamo stiri stvari, jih lahko razvrstimo na 24 nacinov:
  1 2 3 4    1 2 4 3    1 3 2 4   1 3 4 2   1 4 2 3   1 4 3 2
  2 1 3 4    2 1 4 3    2 3 1 4   2 3 4 1   2 4 1 3   2 4 3 1
  3 1 2 4    3 1 4 2    3 2 1 4   3 2 4 1   3 4 1 2   3 4 2 1
  4 1 2 3    4 1 3 2    4 2 1 3   4 2 3 1   4 3 1 2   4 3 2 1

V splosnem, ce imamo n razlicnih stvari: potem imamo n moznosti,
kako si izbrati eno od njih za prvo mesto.  Za drugo mesto potem
ostane n-1 stvari, torej n-1 moznosti.  Za tretje mesto je se
n-2 moznosti in tako naprej.  Vsega skupaj je torej
  n * (n-1) * (n-2) * ... * 3 * 2 * 1
moznosti.  To vrednost oznacujejo tudi z n! (n fakulteta).

Nekaj vrednosti n!:  1! = 1, 2! = 2, 3! = 6, 4! = 24, 5! = 120,
6! = 720, 7! = 5040 in tako naprej.  Obicajno recejo tudi 0! = 1
(ker lahko nic stvari razporedimo na en nacin, namrec tako, da
imamo pac prazno zaporedje).

Bolj uceno bi lahko rekli, da so permutacije bijektivne
preslikave neke mnozice same vase.  Z drugimi besedami,
v vsak element se preslika natanko en element.  To si vsekakor
lahko predstavljamo kot prerazporeditev -- ce je "p" taka
bijektivna preslikava neke mnozice same vase, si lahko mislimo,
da elemente prerazporedi tako, da element a pride po novem na
mesto, kjer je bil prej element p(a).  Permutacijo pogosto
zapisejo tako, da med dva velika oklepaja napisejo kar tabelo,
ki pove, kako se stvari premescajo.  Na primer:
     ( 1 2 3 4 5 )
 p = ( 3 2 4 5 1 ) bi bila permutacija, ki premakne prvi
element na tretje mesto, drugi element pusti pri miru, tretji
element premakne na cetrto mesto, cetrtega na peto, petega
pa na prvo.  Nad permutacijami lahko definiramo tudi nekaksno
mnozenje -- permutacija p*q predstavlja prerazporeditev, kot
jo dobimo, ce najprej izvedemo prerazporeditev q in nato se
prerazporeditev p.  Podobno lahko definiramo p^n = p*p*p*...*p
(n-krat ponovljena prerazporeditev p).  Na primer: ce bi
dvakrat zapored izvedlji gornjo permutacijo p, bi se element
s prvega mesta preslikal najprej na tretje mesto, nato pa
od tam v cetrto.  Torej je p^2(1) enako 4.  Element z drugega
mesta ostane seveda tudi po dveh izvedbah p-ja se vedno na
drugem mestu.  Element s tretjega mesta pride ob prvi izvedbi
p-ja na cetrto, od tam pa v drugi izvedbi na peto mesto.
                                ( 1 2 3 4 5 )
In tako naprej; dobili bi p^2 = ( 4 2 5 1 3 ).

Konkreten primer naloge s permutacijami je 306
(http://acm.uva.es/p/v3/306.html), kjer je v bistvu treba za
dano permutacijo p in dano stevilo n racunati permutacijo p^n.

Pri tejle nalogi z IOI 1996 pa je koristno, ce znamo sistematicno
ostevilciti permutacije (recimo od 0 do n!-1) in potem pretvarjati
stevilke v permutacije in nazaj.
  http://olympiads.win.tue.nl/ioi/ioi96/contest/ioi96m.html
To je podobno kot pri pretvarjanju stevil med razlicnimi bazami
(npr. dvojiska, desetiska, sestnajstiska ipd. stevila), le
da se tu "baza" od cifre do cifre spreminja.

--

Kombinacije

Kombinacije so v bistvu izbori podmnozic.  Na koliko nacinov lahko
izmed n reci izberemo k reci?  Z drugimi besedami: ce vzamemo neko
mnozico z n elementi, koliko podmnozic s k elementi ima ta mnozica?

Na primer: n = 5, k = 3.  Ce imamo recimo mnozico {1, 2, 3, 4, 5},
so njene podmnozice s po tremi elementi naslednje:
  {1, 2, 3}, {1, 2, 4}, {1, 2, 5}, {1, 3, 4}, {1, 3, 5},
  {1, 4, 5}, {2, 3, 4}, {2, 3, 5}, {2, 4, 5}, {3, 4, 5}.

V splosnem lahko recemo takole: najprej izberimo en element.  Za
to je n moznosti.  Potem izberimo se enega od ostalih elementov;
za to je n-1 moznosti.  Potem izberimo se tretji element; za to je
n-2 mozosti.  Itd., itd., in tik preden izberemo se k-ti element,
smo izbrali ze k-1 elementov in imamo neizbranih torej le se
n-(k-1).  Torej imamo za k-ti element n-(k-1) moznosti.  Za zdaj
smo torej dobili n * (n-1) * (n-2) * ... * (n-(k-1)) moznosti.
[Bralec se lahko sam preprica, da bi lahko ta produkt zapisali
tudi kot n! / (n-k)!.]

Toda ker nas zanimajo podmnozice, je vseeno, v kaksnem vrstnem redu
izbiramo njihove elemente.  Ce izberemo najprej element 1, nato
element 3 in koncno element 4, je isto, kot ce bi najprej izbrali
element 4, nato element 1 in koncno element 3 -- v vsakem primeru
dobimo podmnozico {1, 3, 4} (ali pa {4, 1, 3} ali pa {4, 3, 1}
ali pa {1, 4, 3} ali pa {3, 1, 4} ali pa {3, 4, 1} -- saj so vse to
le razlicni zapisi ene in iste podmnozice).

Torej smo za zdaj nasteli ne vseh podmnozic, pac pa vse nacine,
kako izbrati zaporedje k elementov izmed n elementov (mislim, da
temu recejo "variacije").  Kakorkoli ze -- koliko teh nacinov
predstavlja eno in isto podmnozico?  Ocitno toliko, na kolikor
nacinov lahko elemente take podmnozice uredimo v zaporedje.
Teh pa je, kot smo videli v razdelku o permutacijah, ravno k!,
saj gledamo podmnozice s k elementi.  Torej moramo tisti
gornji produkt deliti s k!, ce hocemo, da steje vsako podmnozico
ravno enkrat.

Dobili smo: stevilo kombinacij k elementov iz n elementov je
   C(n, k) = n * (n-1) * (n-2) * ... * (n-(k-1)) / k!.
To lahko zapisemo tudi kot n! / [k! (n-k)!].

Ce na primer v to formulo vstavimo n = 5 in k = 3, dobimo
C(5, 3) = (5 * 4 * 3) / (3 * 2 * 1) = 10, kar potrjuje, da smo
zgoraj pravilno nastevil vse podmnozice s po tremi elementi.

Ce bi za hec izracunali vrednosti C(n, k) za nekaj majhnih n in k:

      k= 0   1   2   3   4   5   6   7
n= 0     1
   1     1   1
   2     1   2   1
   3     1   3   3   1
   4     1   4   6   4   1
   5     1   5  10  10   5   1
   6     1   6  15  20  15   6   1
   7     1   7  21  35  35  21   7   1

in tako naprej.  (Mimogrede, temu trikotniku stevil pravijo tudi
"Pascalov trikotnik".)

Iz tega vidimo nekaj zanimivih lastnosti:

C(n, 0) = 1.  To je pravzaprav cisto razumljivo, saj ima
mnozica z n elementi natancno eno podmnozico z nic elementi --
to je pac prazna mnozica.  Podobno je tudi C(n, n) = 1,
ker je mnozica z n elementi sama svoja podmnozica.

C(n, k) = C(n, n-k).  To vidimo iz tega, da je vsaka vrstica
tabele simetricna.  Isto pa se vidi tudi iz formule: zgoraj smo
ugotovili, da je C(n, k) = n! / [k! (n-k)!].  Ce k spremenimo
v n-k, bosta tako stevec kot imenovalec ostala enaka, saj je
(n-k)! (n-(n-k))! = (n-k)! k! = k! (n-k)!.  Se ena razlaga za
ta pojav je tale: ce izberemo k elementov za neko podmnozico,
je prav isto, kot ce bi rekli, da izberemo n-k elementov, ki jih
bomo pustili pri miru, ostale pa sprejeli v naso podmnozico;
torej je edino smiselno, da dobimo v obeh primerih enako
stevilo izborov, saj v bistvu stejemo iste reci.

C(n, 1) = n.  Tudi to je cisto razumljivo, saj ima mnozica z
n elementi ravno n podmnozic s po enim elementom.

C(n, 2) = n(n-1)/2.  To se vidi iz formule, saj je 2! = 2.

C(n+1, k+1) = C(n, k) + C(n, k+1).  Z drugimi besedami,
vsako stevilo v trikotniku je vsota tistega nad sabo in
tistega levo zgoraj.  (Na primer: 21 = 6 + 15.)  Kako se lahko
prepricamo o tej lastnosti?  No, recimo, da imamo neko mnozico
z n+1 elementi in hocemo izbirati podmnozice s po k+1 elementi.
Glejmo nek konkretni element a.  Ocitno ga lahko ali vzamemo v
nase podmnozice ali pa ga ne vzamemo.  Ce ga vzamemo, moramo
potem izmed preostalih n elementov izbrati se preostalih k
elementov, da bomo imeli skupaj podmnozico s k+1 elementi;
to pa lahko storimo na C(n, k) nacinov.  Ce pa ga ne vzamemo,
moramo potem izmed preostalih n elementov izbrati vseh k+1
elementov za naso podmnozico, to pa lahko storimo na C(n, k+1)
nacinov.  Skupno lahko torej sestavimo podmnozico velikosti k+1
na C(n, k) + C(n, k+1) nacinov.

C(n, 0) + C(n, 1) + ... + C(n, n-1) + C(n) = 2^n.  To se
hitro vidi iz dejstva, da C(n, k) pove, koliko podmnozic s k
elementi ima neka mnozica z n elementi.  Ce to sestejemo za
k-je od 0 do n, smo nasteli ravno vse mozne podmnozice nase
mnozice z n elementi, teh pa je seveda 2^n (za vsak element
imamo 2 moznosi: ali pripada podmnozici ali ne; zato imamo
2*2*2*...*2*2 = 2^n razlicnih podmnozic).

[Tale naslednji dolgi odstavek lahko brez velike skode
preskocite, ce vas ne zanima oz. ce te reci ze poznate.]
Matematiki vrednost C(n, k) radi predstavijo tudi z binomskim
simbolom.  To je velik par oklepajev, vmes pa napisejo n nad
k-jem (kot pri ulomkih, le da brez crte vmes).  Stevilom C(n, k)
pa pravijo tudi binomski koeficienti.  Ta izraz pride od tega,
ker lahko vzamemo binom (dvoclenik), torej izraz oblike (x + y),
pa ga potenciramo na n in nato razvijemo -- dobimo
  (x + y)^n = C(n, 0) x^{n-0} y^0 + C(n, 1) x^{n-1} y^1 +
            + C(n, 2) x^{n-2} y^2 + C(n, 3) x^{n-3} y^3 +
            + .... + C(n, n-2) x^2 y^{n-2} +
            + C(n, n-1) x^1 y^{n-1} + C(n, 0) x^0 y^{n-0}.
Bolj konkretno:
  (x + y)^0 = 1
  (x + y)^1 = x + y
  (x + y)^2 = x^2 + 2xy + y^2
  (x + y)^3 = x^3 + 3 x^2 y + 3 x y^2 + y^3
  (x + y)^4 = x^4 + 4 x^3 y + 6 x^2 y^2 + 4 x y^3 + y^4
in tako naprej.  Skratka, C(n, k) je koeficient ob clenu
x^k y^{n-k} v razvoju izraza (x + y)^n.  Kako se lahko
prepricamo o tem?  No, (x + y)^n lahko zapisemo kot
  (x + y)(x + y)(x + y).......(x + y),
skratka, n-krat skupaj pomnozimo (x + y).  Zdaj pa za
hec pripisimo tem x-om in y-om majhne indekse, da jih bomo
lazje razlikovali med sabo:
  (x_1 + y_1)(x_2 + y_2)(x_3 + y_3)......(x_n + y_n).
Recimo za n = 3:
  (x_1 + y_1)(x_2 + y_2)(x_3 + y_3)
To bi bilo enako
  x_1 x_2 x_3 + x_1 x_2 y_3 + x_1 y_2 x_3 + x_1 y_2 y_3 +
  y_1 x_2 x_3 + y_1 x_2 y_3 + y_1 y_2 x_3 + y_1 y_2 y_3.
Ce bi recimo za vsakega od teh clenov pogledali, na katerih
mestih ima x-e, bi dobili vsakic neko drugo podmnozico
mnozice {1, 2, 3}.  Na primer: iz x_1 x_2 x_3 bi dobili
{1, 2, 3}; iz x_1 x_2 y_3 bi dobili {1, 2}; iz y_1 y_3 x_3
bi dobili {3}; in tako naprej.
  Ker pa v resnici x_1, x_2 in x_3 vsi predstavljajo eno
in isto vrednost, namrec x, in ker podobno y_1, y_2 in y_3 vsi
predstavljajo eno in isto vrednost, namrec y, imajo vsi
cleni z recimo k x-i in (n-k) y-i eno in isto vrednost,
namrec x^k in y^k.  Mi imamo na primer en clen s tremi x-i
(namrec x_1 x_2 x_3), pa tri clene z dvema x-oma in enim y-om
(namrec x_1 x_2 y_3, x_1 y_2 x_3 in y_1 x_2 x_3), tri
clene z enim x-om in dvema y-oma (namrec y_1 y_2 x_3,
y_1 x_2 y_3 in x_1 y_2 y_3) in en clen s tremi y-i (namrec
y_1 y_2 y_3).  Zato dobimo x^3 + 3 x^2 y + 3 x y^2 + y^3,
kar je seveda dobro znana formula za (x + y)^3.
  Ce pa bi gledali v splosnem za (x + y)^n, koliko bi bilo
clenov, ki bi nam dali vrednost x^k y^{n-k}?  To so ocitno
ravno tisti, ki vsebujejo k x-ov in (n-k) y-ov.  Vsakega
od teh clenov pa lahko opisemo z neko podmnozico, ki vsebuje
k elementov iz mnozice {1, 2, ..., n} -- ti elementi bi pac
povedali, katere x-e vsebuje nek nas clen.  In kot smo
videli prej, je takih podmnozic ravno C(n, k).  Zato je tudi
takih clenov pri nas ravno C(n, k) in je zato v koncnem
izrazu koeficient pred x^k y^{n-k} enak ravno C(n, k).

Ce je treba pri kaksni nalogi racunati kaj z vrednostmi C(n, k),
upostevajte, da jih ni nujno najbolj pametno racunati kar po
formuli (n * (n-1) * ... * (n-k+1)) / (k * (k-1) * ... * 2 * 1),
ker lahko stevec (pa tudi imenovalec) tega ulomka hitro
postane precej velik -- cetudi bo rezultat, torej vrednost C(n, k),
mogoce dovolj majhna za 32-bitne spremenljivke, bo stevec mogoce
prevelik in boste imeli zaradi tega tezave.  Zato je vcasih
koristno, ce ta izraz sproti cim bolj okrajsamo.  Posebej
ekstremen primer tega se mi zdi naloga 10329 z valladolidskega
streznika (http://acm.uva.es/p/v103/10329.html).

Skratka, glavna stvar, ki si jo je pametno zapomniti pri
kombinacijah, je pac to, da lahko izmed n razlicnih stvari
izberemo mnozico k razlicnih stvari na C(n, k) = n! / [k! (n-k)!]
nacinov.

Primeri nalog, kjer pridejo prav kombinacije:
  http://acm.uva.es/p/v3/369.html
  http://acm.uva.es/p/v4/417.html
  http://acm.uva.es/p/v102/10232.html

--

Diofantske enacbe

To so enacbe, v katerih nastopajo sama cela stevila in nas tudi
zanimajo celostevilske resitve.  Tu si oglejmo le najpreprostejso
obliko -- linearne diofantske enacbe.

Recimo: 12 x + 18 y = 5
No, leva stran je vedno deljiva s 6 (ce vstavimo celostevilska
x in y), 5 pa ni deljiva s 6, torej ta enacba nima resitev.

Kaj pa: 12 x + 18 y = 30.
Najvecji skupni delitelj 12 in 18 je 6, ki na sreco deli tudi
desno stran enacbe.  Zato bo enacba imela resitve, mi pa jo za
zacetek delimo s 6.
   2x + 3y = 5
    x = (-3y + 5)/2
    x = (-y*2 - y + 2*2 + 1)/2
    x = (-y + 2) + (-y + 1)/2.
Da bo x celo stevilo, mora biti tudi (-y + 1)/2 celo stevilo.
Torej
    z = (-y + 1)/2
  y + 2z = 1
  y = 1 - 2z.
Zdaj lahko vstavimo to se v formulo za x:
  x = (-y + 2) + (-y + 1)/2 = (2z - 1 + 2) + z = 3z + 1.
Skratka, za katerikoli celostevilski z bosta vrednosti
  x = 3z + 1, y = -2z + 1
ustrezali prvotni enacbi.  Poskusimo za hec:
  z = 23, x = 70, y = -45,
  12 * 70 - 18 * 45 = res enako 30.

Poskusimo se eno vecjo:
  54x + 19y + 24z = 121
Vzemimo tisto neznanko, katere koeficient je po absolutni
vrednosti najmanjsi, in nesimo ostale na desno stran:
  19y = -54x - 24z + 121
  y = (-54x - 24z + 121)/19
Zdaj pa tisto v oklepajih razbijmo na kolicnik pri deljenju
z 19 in na ostanek:
  y = (-16x - 2x*19 - 5z - 1z*19 + 7 + 6*19)/19
  y = -2x - z + 6 + (-16x - 5z + 7)/19
Zdaj pa, ce hocemo, da bo y celo stevilo, mora biti tudi
tista cobodra na desni strani celo stevilo.  Torej recimo
  w = (-16x - 5z + 7)/19
  16x + 19w + 5z = 7.
Ta enacba je podobna prvotni, le namesto y ima w;
in medtem ko je imela y prej najmanjsi koeficient (po
absolutni vrednost) -- namrec -19 -- ima w zdaj najvecjega
(16 in 5 sta pac manjsa od 19).  To sploh ni cudno, saj smo
16 in 5 dobili kot ostanka pri deljenju starih koeficientov
z 19.  Zato pa je bilo pametno, da smo izbrali spremenljivko z
najmanjsim koeficientom (namrec 19) -- tako nam koeficienti
najbolj zanesljivo padajo (ostanki pri deljenju z 19 so v
splosnem pac manjsi kot pri deljenju s 24 ali 54).
Prej ali slej bo imela kaksna neznanka koeficient 1,
torej bomo imeli enacbo oblike p = 25q + 35r + 323s + 12345,
kar pa je dejansko ze resitev -- q, r in s si smemo izbrati
poljubno, p pa potem izracunamo po tej enacbi.

Nadaljujemo torej na enak nacin.  Zdaj ima najmanjsi koeficient
(po absolutni vrednosti) z, namrec 5:
  5z = -16x - 19w + 7
  z = (-16x - 19w + 7)/5
  z = (-x - 3x*5 - 4w - 3w*5 + 2 + 1*5)/5
  z = -3x - 3w + 1 + (-x - 4w + 2)/5
Spet moramo zahtevati, da je (-x - 4w + 2)/5 celo stevilo:
  v = (-x - 4w + 2)/5
  x + 4w + 5v = 2
Najmanjsi koeficient, kar 1, ima zdaj x:
  x = -4w - 5v + 2.
Tu pa zdaj, ker imel x koeficient 1 (enako dobro bi seveda bilo,
ce bi imel koeficient -1), na desni strani ni nobenega grdega
ulomka in nase resevanje je s tem koncano.  Resitve prvotne
enacbe bomo dobili, ce bomo vzeli poljubna w in v ter
izracunali x, y in z po formulah:
  x = -4w - 5v + 2,
  z = -3x - 3w + 1 + v,
  y = -2x - z + 6 + w.
Recimo: v = 123, w = 456,
  x = -2347, z = 6067, y = -731,
  54 * (-2347) + 19 * (-731) + 24*6067 = zacuda res 121.

V splosnem bi, ce bi zaceli z n neznankami, na koncu prisli
do situacije, ko lahko eno izrazimo z n-1 ostalimi, nato
pa jih moramo seveda se vstavljati nazaj v enacbe, da vidimo,
kako se vse dotlej izlocene neznanke izrazajo s tistimi n-1,
ki so ostale na koncu.

Ocitno lahko iz opisanega postopka naredimo tudi cisto lepo
sistematicen algoritem -- koeficiente trenutne enacbe bi imel v
neki tabeli, v se eni tabeli (dvodimenzionalni) pa bi hranil
podatke o tem, kako se prvotne spremenljivke izrazajo s trenutnimi
(npr. kako se x, y in z izrazajo z x, w in v).

To lahko posplosimo tudi na sisteme linearnih diofantskih enacb.
Recimo, da imamo m enacb in n neznank.  Recimo prvo enacbo; tedaj
znamo vsako od teh n neznank izraziti z n-1 parametri (na primer:
mi smo zgoraj znali x, y in z izraziti z v in w).  Zdaj vstavimo
to v preostale enacbe in imamo m-1 enacb in n-1 neznank.  Zdaj se
lahko lotimo ene od teh preostalih enacb in tako naprej.

--

Ce imamo samo eno enacbo in dve neznanki, obstaja se enostavnejsi
postopek, ki je v bistvu neka razlicica Evklidovega algoritma:

Imejmo recimo 12x + 29y = 17.  (Ce si koeficienta ob x in y
ne bi bila tuja, bi enacbo najprej delili z najvecjim skupnim
veckratnikom teh dveh koeficientov.  Ce zdaj na desni strani
dobimo necelo stevilo, seveda vemo, da resitev ni.)

(a) No, ce bi vstavili x = 1, y = 0, bi dobili na levi strani 12.
(b) Ce bi vstavili     x = 0, y = 1, bi dobili na levi strani 29.

Ce zdaj delimo 12 z 19, dobimo kolicnik 0.  Zato odstejmo prejsnjo
vrstico 0-krat od predprejsnje:

(c)=(a)-0*(b)          x = 1, y = 0                           12.

Ce zdaj delimo 29 z 12, dobimo kolicnik 2.  Zato odstejmo prejsnjo
vrstico 2-krat od predprejsnje:

(d)=(b)-2*(c)          x = -2, y = 1                           5

(5 je seveda ravno ostanek pri deljenju 29 z 12.)  Ce zdaj delimo
12 s 5, dobimo spet kolicnik 2 in zato dvakrat odstejmo prejsnjo
vrstico od predprejsnje:

(e)=(c)-2*(d)          x = 5, y = -2                           2

(f)=(d)-2*(e)         x = -12, y = 5                           1

Tako smo torej videli, da pri x = -12 in y = 5 dobimo
12x + 29y = 1.  Ce hocemo dobiti na desni strani 17, moramo vzeti
x = -12*17 = -204 in y = 5*17 = 85.  Toda poleg tega, ce povecamo
x za 29, y pa zmanjsamo za 12, bo seveda 12x + 29y ostala
nespremenjena (saj se bo najprej povecala za 12*29 in nato
zmanjsala za 29*12).  Zato je resitev v resnici vsak par
(x, y) oblike      x = -204 + 29*k,   y = 85 - 12*k.

Kaksno zvezo ima to z Evklidovim algoritmom?  Ce pogledate po
dve zaporedni stevilki v skrajnem desnem stolpcu, dobite ravno
pare, kot bi jih gledal Evklidov algoritem, ce bi mu dali
racunati gcd(12, 29).  Ta bi namrec ugotovil, da je
  gcd(12, 29) = gcd(29, 12 mod 29) =
= gcd(29, 12) = gcd(12, 29 mod 12) =
= gcd(12, 5) = gcd(5, 12 mod 5) =
= gcd(5, 2) = gcd(2, 2 mod 5) =
= gcd(2, 1) = 1.  Rezultat pa ze tako ali tako vemo, da bo 1,
saj smo ze na zacetku poskrbeli, da sta si koeficienta ob
x in y tuja.

procedure Diof(A, B, C: Integer);
var D, I: Integer;
    AA, BB, CC: array[0..1] of Integer;
begin
  D := gcd(A, B);
  if (C mod D) <> 0 then
    begin WriteLn('Ni resitev.'); Exit; end;
  A := A div D; B := B div D; C := C div D;
  AA[0] := 1; BB[0] := 0; CC[0] := A;
  AA[1] := 0; BB[1] := 1; CC[1] := B;
  I := 1;
  while CC[I] > 1 do
    begin
    I := 1-I; D := CC[I] div CC[1-I];
    AA[I] := AA[I] - D * AA[1-I];
    BB[I] := BB[I] - D * BB[1-I];
    CC[I] := CC[I] - D * CC[1-I];
    end;
  WriteLn('x = ', AA[I] * C, ' + ', B, ' * k');
  WriteLn('y = ', AA[I] * C, ' -', A, ' * k');
end;

Demo tega algoritma je na
http://www.student.math.uwaterloo.ca/~madrewbr/lde.html .

Diofantske enacbe bi prisle prav na primer pri nalogi
  http://acm.uva.es/p/v7/718.html ,
pa tudi pri http://acm.uva.es/p/v4/463.html .

Ce se bo kdo navdusil nad diofantskimi enacbami, priporocam knjizico
"Diofantske enacbe" Jozeta Grassellija.
